<?php
/**
 * 2020-11-03 更改为PDO 全部数据进行预处理
 */

namespace diablo\lib;

use diablo\lib\Config;

class Model
{
    private $conn;
    private $tableName;
    private $where = "";
    private $groupBy = [];
    private $orderBy = [];
    private $limit = "";
    private $toSql = "";
    private $preproArray = []; //预处理数组
    private $index = null;//数组下标格式指定


    public function __construct($database = false)
    {
        if (empty($database)) {
            $database = Config::get('database');
        }
        try {
            //编码集
            $dsn = "mysql:dbname={$database['DB_NAME']};host={$database['DB_HOST']}";
            $this->conn = new \PDO($dsn, $database['USERNAME'], $database['PASSWORD']);
            $this->conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
            $this->conn->query('set names utf8');
        } catch (\Exception $e) {
            Logger::setLog($e->getMessage());
        }
    }

    //表名
    public function table($tableName)
    {
        $this->tableName = $tableName;
        return $this;
    }

    //条件 默认是 =
    public function where($arr)
    {
        //获取一个随机数防止冲突
        $oneStr = $arr[0] . mt_rand(10, 99);
        $where = "";
        //有自定义条件
        if (count($arr) > 2) {
            $where = " and `" . $arr[0] . "` " . $arr[1] . " :{$oneStr} ";
            array_push($this->preproArray, [$oneStr => $arr[2]]);
        } else {//无自定义条件
            $where = " and `" . $arr[0] . "` = :{$oneStr} ";
            array_push($this->preproArray, [$oneStr => $arr[1]]);
        }
        $this->where .= $where;
        return $this;
    }

    //同字段 多条件
    public function whereIn($key, $arr)
    {
        $keys = $key;
        $str = "";
        $strArr = [];
        foreach ($arr as $key => $vo) {
            //随机数防止冲突
            $num = mt_rand(10, 99);
            $str .= ":" . $keys . $num . ",";
            $strArr[$keys . $num] = $vo;
        }
        $str = substr($str, 0, strlen($str) - 1);
        //获取一个随机数防止冲突
        $where = " and " . $keys . " in ({$str}) ";
        array_push($this->preproArray, $strArr);
        $this->where .= $where;
        return $this;
    }

    //分组
    public function groupBy($str)
    {
        $this->groupBy[] = $str;
        return $this;
    }

    //排序
    public function orderBy($str, $px = "desc")
    {
        $this->orderBy[] = "$str $px";
        return $this;
    }

    //分页查询
    public function limit($page, $limit = null)
    {
        $this->limit = $limit ? " limit " . $page . "," . $limit : " limit " . $page;
        return $this;
    }

    //查询指定下标
    public function index($key = null)
    {
        if (empty($key)) {
            throw new \Exception('index填入的值不能为空！');
        }
        $this->index = $key;
        return $this;
    }

    //查询所有
    public function select($p = "*")
    {
        if (empty($p)) {
            throw new \Exception("前缀不能为空！");
        }
        $this->orderBy = empty($this->orderBy) ? "" : " order by " . implode(',', $this->orderBy);
        $this->groupBy = empty($this->groupBy) ? "" : " group by " . implode(',', $this->groupBy);
        $sql = "select " . $p . " from " . $this->tableName . " where 1=1 " . $this->where . $this->groupBy . $this->orderBy . $this->limit;
        //预处理防止sql注入
        $res = $this->query($sql);
        $res->execute();
        $data = $res->fetchAll(\PDO::FETCH_ASSOC);
        $this->toSql = $sql;
        return $this->outData($data);
    }

    //查询一条结果
    public function count()
    {
        $sql = "select count(0) num from " . $this->tableName . " where 1=1 " . $this->where . " limit 1 ";
        $res = $this->query($sql);
        $res->execute();
        $data = $res->fetch(\PDO::FETCH_ASSOC);
        $this->toSql = $sql;
        return $data['num'];
    }

    //查询一条结果
    public function selectOne($p = "*")
    {

        if (empty($p)) {
            throw new \Exception("前缀不能为空！");
        }
        $this->orderBy = empty($this->orderBy) ? "" : " order by " . implode(',', $this->orderBy);
        $this->groupBy = empty($this->groupBy) ? "" : " group by " . implode(',', $this->groupBy);
        $sql = "select " . $p . " from " . $this->tableName . " where 1 " . $this->where . $this->orderBy . " limit 1 ";
        $res = $this->query($sql);
        $res->execute();
        $data = $res->fetch(\PDO::FETCH_ASSOC);
        if (!$data) {
            return null;
        }
        $this->toSql = $sql;
        return $this->outData($data);
    }

    //查询多条结果
    public function find($sql, $arr = [])
    {
        $res = $this->conn->prepare($sql);
        foreach ($arr as $key => $vo) {
            $res->bindValue($key, $vo);
        }
        $res->execute();
        $data = $res->fetchAll(\PDO::FETCH_ASSOC);
        return $this->outData($data);
    }

    //查询单条结果
    public function get($sql, $arr = [])
    {
        $res = $this->conn->prepare($sql);
        foreach ($arr as $key => $vo) {
            $res->bindValue($key, $vo);
        }
        $res->execute();
        $data = $res->fetch(\PDO::FETCH_ASSOC);
        return $this->outData($data);
    }

    //操作执行结果集
    public function raw($sql, $arr = [])
    {
        $res = $this->conn->prepare($sql);
        foreach ($arr as $key => $vo) {
            $res->bindValue($key, $vo);
        }
        $res->execute();
        $res->fetch(\PDO::FETCH_ASSOC);
        return $res->rowCount();
    }

    //执行一条sql 并返回执行结果条数
    public function query($sql)
    {
        $res = $this->conn->prepare($sql);
        //绑定参数
        foreach ($this->preproArray as $row) {
            foreach ($row as $key => $vo) {
                $res->bindValue(':' . $key, $vo);
            }
        }
        $this->toSql = $sql;
        return $res;
    }

    //添加
    public function insert($arr, $lx = false)
    {
        $k = $v = [];
        foreach ($arr as $key => $vo) {
            $k[] = $key;
            //获取一个随机数防止冲突
            $oneStr = $key . mt_rand(10, 99);
            $v[] = ":" . $oneStr;
            array_push($this->preproArray, [$oneStr => $vo]);
        }
        $k = implode(',', $k);
        $v = implode(',', $v);
        $sql = "insert into " . $this->tableName . " (" . $k . ") values (" . $v . ") ";
        $res = $this->query($sql);
        $res->execute();
        if ($lx) {
            $res = $this->query("SELECT LAST_INSERT_ID() num");
            $res->execute();
            $data = $res->fetch(\PDO::FETCH_ASSOC);
            $row = $data["num"];
        } else {
            $row = $res->rowCount();
        }
        $this->end_callback();
        return $row;
    }

    //删除
    public function delete()
    {
        $sql = "delete from " . $this->tableName . " where 1 " . $this->where;
        $res = $this->query($sql);
        $res->execute();
        $row = $res->rowCount();
        $this->end_callback();
        return $row;
    }

    //更新
    public function update($arr)
    {
        $v = [];
        foreach ($arr as $key => $vo) {
            //获取一个随机数防止冲突
            $oneStr = $key . mt_rand(10, 99);
            $v[] = "`" . $key . "` = :" . $oneStr;
            array_push($this->preproArray, [$oneStr => $vo]);
        }
        $v = implode(',', $v);
        $sql = "update " . $this->tableName . " set " . $v . " where 1 " . $this->where;
        $res = $this->query($sql);
        $res->execute();
        $row = $res->rowCount();
        $this->end_callback();
        if ($row) {
            return 1;
        }
        return 0;
    }

    //返回sql数据
    public function toSql()
    {
        return $this->toSql;
    }

    //前缀映射规则变更数据输出后需要处理
    private function outData($data)
    {
        $index = $this->index;
        $this->end_callback();
        if (!empty($index)) {
            $indexArr = [];
            foreach ($data as $key => $vo) {
                if (is_array($vo)) {
                    $indexArr[$vo[$index]] = $vo;
                }
            }
            return $indexArr ?: $data;
        }
        return $data;
    }

    //结束回调
    private function end_callback()
    {
        //初始化
        $this->preproArray = [];
        $this->where = "";
        $this->limit = "";
        $this->orderBy = [];
        $this->groupBy = [];
        $this->tableName = "";
        $this->index = "";
    }

}